from fastapi import FastAPI, Query, Form,File,UploadFile,HTTPException,Request

from typing import Union,Annotated, Literal
from pydantic import BaseModel, Field, EmailStr
from starlette import status

app = FastAPI()

@app.get("/")
async def root():
    return {"Hello": "World_app"}

class FilterParams(BaseModel):
    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items5/",status_code=status.HTTP_201_CREATED)
#更改默认状态码 为201
async def read_items(filter_query: Annotated[FilterParams, Query()]):
    #需要传入的是查询参数，使用 Annotated,系统会自动解构变成 FilterParams
    return filter_query



class UserBase(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None

class UserIn(UserBase):
    password: str

class UserOut(UserBase):
    pass

class UserInDB(UserBase):
    hashed_password: str

def fake_password_hasher(raw_password: str):
    return "supersecret" + raw_password

def fake_save_user(user_in: UserIn):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB(** user_in.dict(),hashed_password = hashed_password)
    print("User saved!  ..not really")
    return user_in_db

@app.post("/items131/user/",response_model=UserOut)
async def create_user(user: UserIn):
    user_saved = fake_save_user(user)
    return user_saved

class BaseItem(BaseModel):
    description: str
    type: str

class CarItem(BaseItem):
    type: str = "car"

class PlaneItem(BaseItem):
    type: str = "plane"
    size: int

items = {
    "item1": {"description": "All my friends drive a low rider", "type": "car"},
    "item2": {
        "description": "Music is my aeroplane, it's my aeroplane",
        "type": "plane",
        "size": 5,
    },
}

@app.post("/items132/{item_id}", response_model=Union[PlaneItem, CarItem])
async def read_item(item_id: str):
    print(item_id)
    return items[item_id]

@app.post("/items140/")
async def login(username: str = Form(), password: str = Form()):
    return {"username": username,"password": password}



class FromData(BaseModel):
    username: str
    password: str
    model_config = {"extra": "allow"}    #禁止额外的表当域

@app.post("/items142/")
async def login(data: Annotated[FromData, Form()]):
    return data

@app.post("/items151/")
async def create_file(file: bytes = File()):
    return {"file_size": len(file), "file": file}

@app.post("/items152/")
async def create_upload_file(file: UploadFile):
    contents = await file.read()   #读取文件内容
    return {"filename": file.filename,"content_type":file.content_type
    ,"file":contents.decode("utf-8")}

@app.post("/items153/")
async def create_file(
	file: bytes = File(), file_b: UploadFile = File(), token: str = Form()
):
    """  上传文件并接收 token。"""
    return{
        "file_size": len(file),
        "token": token,
        "file_b_content_type": file_b.content_type,
    }

items160 = {"foo": "The Foo Wrestlers"}
@app.post("/items160/{item_id}")
async def read_item(item_id: str):
    """
    处理错误，抛出异常 使用 raise
    :param item_id:
    :return: 返回有值的参数，没有返回 Item not found
    """
    if item_id not in items160:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items160[item_id]}

items162 = {"foo": "The Foo Wrestlers162"}

@app.post("/items162/{item_id}")
async def read_item_header(item_id: str):
    if item_id not in items162:
        raise HTTPException(
        status_code=404,
        detail= "Item not found",
        headers= {"X-Error": "There goes my error"} )
    return {"item": items162[item_id]}

from fastapi.responses import JSONResponse


class UnicornException(Exception):
    def __init__(self, name: str):
        self.name = name


@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
    return JSONResponse(
    	status_code=418,
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
    )
@app.post("/items163/{name}")
async def read_unicorn(name: str):
    """
    请求 /items163/yolo时， 路径操作会触发 UnicornException,
        但该异常将会被 unicorn_exception_handler 处理
    :param name:
    :return:
    """
    if name == "yolo":
        raise UnicornException(name=name)
    return {"unicorn_name": name}




